package com.tbit.uqbike.service.rpcservice.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tbit.uqbike.constant.MachineAbnormalConstant;
import com.tbit.uqbike.constant.UserConstant;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.business.CalibrateUtils;
import com.tbit.uqbike.object.business.PageData;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.MachineOperationsStatDownloadDTO;
import com.tbit.uqbike.object.pojo.statistics.ExportMachine;
import com.tbit.uqbike.object.pojo.vo.MachineOperationsStatChartVO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.base.CalibrateService;
import com.tbit.uqbike.service.base.MachineService;
import com.tbit.uqbike.service.rpcservice.MachineManagerService;
import com.tbit.uqbike.service.rpcservice.PurviewService;
import com.tbit.uqbike.webmanager.business.vehicle_operation_report.enums.TimeDuration;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.stat.MachineOperationsStatDao;
import com.tbit.uqbike.webmanager.util.StringUtil;
import com.tbit.uqbike.webmanager.util.csv.CsvExportUtils;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.support.RequestContext;

import javax.annotation.Resource;
import java.io.File;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

/**
 * @author MyWin E-mail:335918956@qq.com
 * @version 1.0
 * @createTime 2019-12-10 15:00
 */
@Slf4j
@Service
public class MachineManagerServiceImpl implements MachineManagerService {
    @Autowired
    private MachineStatusDao machineStatusDao;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private PurviewService purviewService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private StatDataDao statDataDao;
    @Autowired
    private AccountUserDao accountUserDao;
    @Autowired
    private AccountConfigDao accountConfigDao;
    @Autowired
    private MachineSuperviseDao machinesuperviseDao;
    @Autowired
    private MachineDao machineDao;
    @Resource
    private MachineOperationsStatDao machineOperationsStatDao;
    @Resource
    private CsvExportUtils csvExportUtils;

    private void purviewCheck(LoginInfo info, Integer accountId) {
        Account opAcc = accountDao.getByAccountId(info.id);
        Account obj = accountDao.getByAccountId(accountId);
        if (null == obj || !Objects.equals(obj.getType(), UserConstant.USER_AGENT)) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        if (!purviewService.purviewCheck(opAcc, obj)) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
    }

    private List<Integer> filterAccountIds(Account opAcc, List<Integer> accountIds) {
        if (null == opAcc) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        if (Objects.equals(opAcc.getType(), UserConstant.USER_FRANCHISEE) || Objects.equals(opAcc.getType(), UserConstant.USER_BRAND)
                || Objects.equals(opAcc.getType(), UserConstant.USER_AGENT) || Objects.equals(opAcc.getType(), UserConstant.USER_ADMIN)) {
            return purviewService.filterAgent(opAcc, accountIds);
        } else {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
    }

    @Override
    public MachineStatusFlag getByKey(LoginInfo info, Integer accountId, String key, Integer mapType) {
        Machine machine = machineService.getByUserCode(key);
        if (null == machine) {
            throw new BaseException(SystemCodeEnum.MACHINE_NOT_EXIST);
        }
        /**车辆是否属于本搜索的运营区域*/
        if (accountId != null && !accountId.equals(machine.getAccountId())) {
            throw new BaseException(SystemCodeEnum.MACHINE_NOT_EXIST);
        }

        if (!purviewService.purviewCheck(info.id, machine)) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machine.getMachineId());
        map.put("sortByBatDt", false);
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);
        if (null != machineStatusFlags && !machineStatusFlags.isEmpty()) {
            return machineStatusFlags.get(0);
        }

        return null;
    }

    @Override
    public PageData<List<MachineStatusFlag>> getByPower(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer soc, Integer mapType,
                                                        Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionList) {
        purviewCheck(info, accountId);
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("socPercent", soc);
        map.put("machineType", machineType);
        map.put("sortByLast", sortByLast);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);
        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        return new PageData<>(machineStatusFlags, total);
    }

    @Override
    public synchronized PageData<List<MachineStatusFlag>> getAll(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer mapType, Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionList) {
        purviewCheck(info, accountId);
        Map<String, Object> params = new HashMap<>(8);
        params.put("accountUserId", info.getAccountUserId());
        params.put("accountId", accountId);
        params.put("subRoleType", StringUtil.getIntegerList("2,9"));
        AccountUserBound customer = accountUserDao.getCustomer(params);

        Map<String, Object> map = new HashMap<>(8);
        map.put("accountId", accountId);
        map.put("machineType", machineType);
        map.put("sortByLast", sortByLast);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        if (customer != null) {
            Integer virtualCarNum = accountConfigDao.getById(accountId).getVirtualCarNum();
            List<Machinesupervise> list = new ArrayList<>();
            List<Machinesupervise> carNumber = machinesuperviseDao.queryById(accountId);
            if (virtualCarNum != carNumber.size()) {
                machinesuperviseDao.deleteById(accountId);
                List<Machine> machines = machineDao.selectById(accountId);
                machines = chooseReturnMachines(machines, virtualCarNum);
                machines.forEach(machine -> list.add(new Machinesupervise(machine.getAccountId(), machine.getMachineId(), new Date())));
                machinesuperviseDao.insertBatch(list);
            }
            map.put("supervision", 1);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);
        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        return new PageData<>(machineStatusFlags, total);
    }

    /**
     * 选择返回的车辆
     *
     * @param machines      车辆列表
     * @param virtualCarNum 监管绑定车辆数
     */
    List<Machine> chooseReturnMachines(List<Machine> machines, Integer virtualCarNum) {
        int machineSize = machines.size();
        virtualCarNum = machineSize > virtualCarNum ? virtualCarNum : machineSize;
        if (machineSize == virtualCarNum) {
            return machines;
        }
        List<Machine> newMachineList = new LinkedList<>();
        for (int i = 0, j = machineSize - 1, count = 0; i < j; i++, j--, count += 2) {
            newMachineList.add(machines.get(i));
            if (newMachineList.size() == virtualCarNum) {
                break;
            }
            newMachineList.add(machines.get(j));
            if (newMachineList.size() == virtualCarNum) {
                break;
            }
        }
        return newMachineList;
    }


    @Override
    public PageData<List<MachineStatusFlag>> getByUnuse(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer hours, Integer mapType,
                                                        Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionIdList) {
        purviewCheck(info, accountId);
        Date lastBorrowTime = new Date(System.currentTimeMillis() - hours * 3600 * 1000);
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("lastBorrowTime", lastBorrowTime);
        map.put("machineType", machineType);
        map.put("sortByLast", sortByLast);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionIdList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);

        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        for (MachineStatusFlag machineStatusFlag : machineStatusFlags) {
            machineStatusFlag.setRegionName(accountUserDao.getRegionName(machineStatusFlag.getRegionId()));
        }
        return new PageData<>(machineStatusFlags, total);
    }

    @Override
    public PageData<List<MachineStatusFlag>> getByFault(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer mapType, Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionList) {
        purviewCheck(info, accountId);
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("faultFlag", true);
        map.put("machineType", machineType);
        map.put("sortByLast", sortByLast);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);

        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        return new PageData<>(machineStatusFlags, total);
    }

    @Override
    public PageData<List<MachineStatusFlag>> getByAbnormal(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer abnormalType, Integer mapType,
                                                           Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionList) {
        purviewCheck(info, accountId);
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("abnormalType", abnormalType);
        map.put("abnormalFlag", true);
        map.put("machineType", machineType);
        map.put("sortByLast", sortByLast);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);

        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        return new PageData<>(machineStatusFlags, total);
    }

    @Override
    public Map<String, Integer> statAbnormal(LoginInfo info, Integer accountId, List<Integer> regionList) {
        purviewCheck(info, accountId);
        Map<String, Object> param = new HashMap<>();

        Map<String, Integer> map = new HashMap<>();
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY.toString(), 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_ZW.toString(), 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_WXH.toString(), 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_DCYC.toString(), 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_JTQ.toString(), 0);

        param.put("accountId", accountId);
        param.put("regionList", regionList);
        /**选择分区后查询车辆异常*/
        if (regionList != null && regionList.size() > 0) {
            List<NameCount> nameCountList = machineStatusDao.statAbnormalByRegionId(param);
            for (NameCount nc : nameCountList) {
                String key = nc.getName();
                map.put(key, nc.getC1());
            }
            return map;
        }
        List<NameCount> nameCountList = machineStatusDao.statAbnormal(param);
        for (NameCount nc : nameCountList) {
            String key = nc.getName();
            map.put(key, nc.getC1());
        }
        return map;
    }

    @Override
    public Map<String, Integer> statAbnormal(LoginInfo info, List<Integer> accountIds) {
        Account opAcc = accountDao.getByAccountId(info.id);
        List<Integer> rightIds = filterAccountIds(opAcc, accountIds);
        Map<String, Integer> map = new HashMap<>();
        if (rightIds.isEmpty()) {
            return map;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("accountIds", rightIds);

        List<NameCount> nameCountList = machineStatusDao.statAbnormalByIds(param);

        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY_NAME, 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_ZW_NAME, 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_WXH_NAME, 0);
        map.put(MachineAbnormalConstant.MACHINE_ABNORMAL_DCYC_NAME, 0);
        for (NameCount nc : nameCountList) {
            String key = nc.getName();
            String name = null;
            if (Objects.equals(key, MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY.toString())) {
                name = MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY_NAME;
            } else if (Objects.equals(key, MachineAbnormalConstant.MACHINE_ABNORMAL_ZW.toString())) {
                name = MachineAbnormalConstant.MACHINE_ABNORMAL_ZW_NAME;
            } else if (Objects.equals(key, MachineAbnormalConstant.MACHINE_ABNORMAL_WXH.toString())) {
                name = MachineAbnormalConstant.MACHINE_ABNORMAL_WXH_NAME;
            } else if (Objects.equals(key, MachineAbnormalConstant.MACHINE_ABNORMAL_DCYC.toString())) {
                name = MachineAbnormalConstant.MACHINE_ABNORMAL_DCYC_NAME;
            }
            if (null != name) {
                map.put(name, nc.getC1());
            }
        }
        return map;
    }

    @Override
    public Map<String, Integer> statIdle(LoginInfo info, List<Integer> accountIds) {
        Account opAcc = accountDao.getByAccountId(info.id);
        List<Integer> rightIds = filterAccountIds(opAcc, accountIds);

        if (rightIds.isEmpty()) {
            return new HashMap<>();
        }
        List<NameCount> list = statDataDao.statCarIdle(rightIds);
        Map<String, Integer> map = new HashMap() {
            {
                put("idle.short", 0);
                put("idle.mid", 0);
                put("idle.long", 0);
                put("idle.longlong", 0);
            }
        };
        for (NameCount item : list) {
            map.put(String.format("idle.%s", item.getName()), item.getC1());
        }
        // 不需要总数显示
        // int total = statDataDao.countCars(rightIds);
        // map.put(String.format("idle.%s", NameObject.PRO_TOTAL), total);
        return map;
    }

    @Override
    public Map<String, Integer> statBattery(LoginInfo info, List<Integer> accountIds) {
        Account opAcc = accountDao.getByAccountId(info.id);
        List<Integer> rightIds = filterAccountIds(opAcc, accountIds);

        if (rightIds.isEmpty()) {
            return new HashMap<>();
        }
        List<NameCount> list = statDataDao.statCarBattery(rightIds);
        Map<String, Integer> map = new HashMap() {
            {
                put("bat.unkonwn", 0);
                put("bat.normal", 0);
                put("bat.mid", 0);
                put("bat.low", 0);
            }
        };
        for (NameCount item : list) {
            map.put(String.format("bat.%s", item.getName()), item.getC1());
        }
        // 不需要总数显示
        // int total = statDataDao.countCars(rightIds);
        // map.put(String.format("bat.%s", NameObject.PRO_TOTAL), total);
        return map;
    }

    @Override
    public Map<String, Integer> statAllState(LoginInfo info, List<Integer> accountIds) {
        Account opAcc = accountDao.getByAccountId(info.id);
        List<Integer> rightIds = filterAccountIds(opAcc, accountIds);

        if (rightIds.isEmpty()) {
            return new HashMap<>();
        }
        List<BikeStatus> bsList = statDataDao.statCarStatus(rightIds);
        Map<String, Integer> map = BikeStatus.initMap();
        for (BikeStatus bs : bsList) {
            BikeStatus.statItem(map, bs);
        }
        // 不需要总数显示
        map.remove(BikeStatus.PRO_TOTAL);
        return map;
    }

    @Override
    public PageData<List<MachineStatusFlag>> getByUse(LoginInfo info, Boolean sortByLast, Boolean sortByBatDt, Boolean sortByPosDt, Integer accountId, Integer mapType,
                                                      Integer rowCount, Integer pageNO, Integer machineType, List<Integer> regionIdList) {
        purviewCheck(info, accountId);
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("use", true);
        map.put("sortByLast", sortByLast);
        map.put("machineType", machineType);
        map.put("sortByBatDt", sortByBatDt);
        map.put("sortByPosDt", sortByPosDt);
        map.put("regionList", regionIdList);
        boolean page = null != rowCount && null != pageNO;
        if (page) {
            map.put("start", rowCount * (pageNO - 1));
            map.put("rowCount", rowCount);
        }
        List<MachineStatusFlag> machineStatusFlags = machineStatusDao.getMachineStatusFlagByAccId(map);
        // 校准
        CalibrateUtils.calibrateObjects(calibrateService, machineStatusFlags, mapType);

        Integer total = null;
        if (page) {
            total = machineStatusDao.getMachineStatusCntFlagByAccId(map);
        }
        return new PageData<>(machineStatusFlags, total);
    }

    @Override
    public Page<MachineOperationsStat> selectMachineOperationsStatPage(String accountIds, String startTime, String endTime,
                                                                       String orderBy, Integer rowCount, Integer pageNO, TimeDuration duration) {
        LambdaQueryWrapper<MachineOperationsStat> lambdaQueryWrapper = buildQueryWrapper(accountIds, startTime, endTime, duration);
        lambdaQueryWrapper.orderBy(true, "ASC".equalsIgnoreCase(orderBy), MachineOperationsStat::getId);
        return machineOperationsStatDao.selectPage(new Page<>(pageNO, rowCount), lambdaQueryWrapper);
    }

    @Override
    public List<MachineOperationsStatChartVO> selectMachineOperationsStatChart(String accountIds, String startTimeStr,
                                                                               String endTimeStr, Integer dateType) {
        List<Integer> accountIdList = Arrays.stream(accountIds.split(","))
                .map(Integer::valueOf)
                .collect(toList());
        List<Account> accounts = accountDao.getByAccountIds(accountIdList);
        if (accounts.isEmpty()) {
            return Collections.emptyList();
        }
        List<String> dateKeys;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
        Function<MachineOperationsStatChartVO.MachineOperationsStatVO, String> groupKeyFn;
        switch (dateType) {
            case 1:
                dateKeys = DateTimeUtil.generateDateHourList(startTimeStr, endTimeStr, true);
                groupKeyFn = stat -> stat.getDateStr() + "_" + stat.getTimeSlot() + "_" + stat.getAccountId();
                break;
            case 2:
                LocalDateTime parsedEndTime = LocalDateTime.parse(endTimeStr, dateTimeFormatter);
                dateKeys = DateTimeUtil.getBetweenEveryDay(Timestamp.valueOf(LocalDateTime.parse(startTimeStr, dateTimeFormatter)),
                        Timestamp.valueOf(parsedEndTime));
                if (parsedEndTime.getHour() == 0) {
                    dateKeys.remove(dateKeys.size() - 1);
                }
                groupKeyFn = stat -> stat.getDateStr() + "_" + stat.getAccountId();
                break;
            case 3:
                dateKeys = DateTimeUtil.getMonth(startTimeStr, endTimeStr);
                if (DateTimeUtil.isStartOfMonth(Timestamp.valueOf(LocalDateTime.parse(endTimeStr, dateTimeFormatter)))) {
                    dateKeys.remove(dateKeys.size() - 1);
                }
                groupKeyFn = stat -> stat.getDateStr() + "_" + stat.getAccountId();
                break;
            default:
                dateKeys = Collections.emptyList();
                groupKeyFn = stat -> stat.getDateStr() + "_" + stat.getTimeSlot() + "_" + stat.getAccountId();
        }

        Map<String, MachineOperationsStatChartVO.MachineOperationsStatVO> resultMap = machineOperationsStatDao
                .selectMachineOperations(accountIdList, startTimeStr, endTimeStr, dateType)
                .stream()
                .collect(toMap(groupKeyFn, Function.identity()));

        List<MachineOperationsStatChartVO> resultList = new ArrayList<>();
        for (Account account : accounts) {
            Integer accountId = account.getAccountId();
            String accountName = account.getName();
            MachineOperationsStatChartVO chartVO = new MachineOperationsStatChartVO(accountId, accountName);
            dateKeys.forEach(dateKey -> {
                String groupKey = dateKey + "_" + accountId;
                MachineOperationsStatChartVO.MachineOperationsStatVO statVO = resultMap.get(groupKey);
                if (Objects.isNull(statVO)) {
                    String[] keys = dateKey.split("_");
                    statVO = (dateType == 1) ? new MachineOperationsStatChartVO.MachineOperationsStatVO(accountId, keys[0], Integer.valueOf(keys[1])) :
                            new MachineOperationsStatChartVO.MachineOperationsStatVO(accountId, keys[0]);
                }
                chartVO.addData(statVO);
            });
            resultList.add(chartVO);
        }
        return resultList;
    }

    /**
     * 车辆状态统计列表导出
     * @param dto 入参
     * @return 文件名
     */
    @Override
    public Result<Object> machineOperationsStatExport(MachineOperationsStatDownloadDTO dto) {
        LambdaQueryWrapper<MachineOperationsStat> lambdaQueryWrapper = buildQueryWrapper(dto.getAccountIds(), DateUtil.formatDateTime(dto.getStartTime()), DateUtil.formatDateTime(dto.getEndTime()), dto.getDuration());
        lambdaQueryWrapper.orderBy(true, "ASC".equalsIgnoreCase(dto.getOrderBy()), MachineOperationsStat::getAddTime);
        List<MachineOperationsStat> dataResult = machineOperationsStatDao.selectList(lambdaQueryWrapper);
        String fileName = String.format("%s~%s_车辆状态统计", DateUtil.formatDate(dto.getStartTime()), DateUtil.formatDate(dto.getEndTime()));
        ExcelUtil<MachineOperationsStat> excelUtil = new ExcelUtil(MachineOperationsStat.class);
        return Result.success(excelUtil.exportExcel(dataResult, fileName).getData());
    }

    private LambdaQueryWrapper<MachineOperationsStat> buildQueryWrapper(String accountIds, String startTime, String endTime, TimeDuration duration) {
        LambdaQueryWrapper<MachineOperationsStat> wrapper = Wrappers.lambdaQuery(MachineOperationsStat.class)
                .in(accountIds.contains(","), MachineOperationsStat::getAccountId,
                        Arrays.stream(accountIds.split(",")).map(Integer::valueOf).collect(Collectors.toSet()))
                .eq(!accountIds.contains(","), MachineOperationsStat::getAccountId, accountIds)
                .ge(StringUtils.isNotBlank(startTime), MachineOperationsStat::getAddTime, startTime)
                .lt(StringUtils.isNotBlank(endTime), MachineOperationsStat::getAddTime, endTime);
        if (duration == TimeDuration.HOUR) {
            wrapper.gt(MachineOperationsStat::getTimeSlot, 0);
        } else {
            wrapper.eq(MachineOperationsStat::getTimeSlot, 0);
        }

        return wrapper;
    }

    @Override
    public String machineOperationsStatExportCsv(MachineOperationsStatDownloadDTO downloadDTO) {
        File tempFile = csvExportUtils.getTempFile();
        String accountIds = downloadDTO.getAccountIds();
        String startTime = DateUtil.formatDateTime(downloadDTO.getStartTime());
        String endTime = DateUtil.formatDateTime(downloadDTO.getEndTime());
        LambdaQueryWrapper<MachineOperationsStat> lambdaQueryWrapper = buildQueryWrapper(accountIds, startTime, endTime, downloadDTO.getDuration());
        lambdaQueryWrapper.orderBy(true, "ASC".equalsIgnoreCase(downloadDTO.getOrderBy()), MachineOperationsStat::getAddTime);
        List<MachineOperationsStat> dataResult = machineOperationsStatDao.selectList(lambdaQueryWrapper);
        try {
            File file = csvExportUtils.exportCsv(MachineOperationsStat.class, tempFile,
                    downloadDTO.getFileName(), dataResult, false);
            String uploadFileName = UUID.randomUUID().toString().replace("-", "");
            //压缩文件并上传oss
            return csvExportUtils.uploadZip(tempFile, uploadFileName, file);
        } finally {
            //删除临时文件
            FileUtil.del(tempFile);
        }
    }

    @Override
    public List<ExportMachine> export(PageData<List<MachineStatusFlag>> pageDatas, RequestContext context) {
        List<ExportMachine> exports = new ArrayList<>();
        pageDatas.getData().forEach(machineStatusFlag -> {
            StringBuilder str = new StringBuilder();
            ExportMachine machine = new ExportMachine();
            machine.setMachineType(machineStatusFlag.getMachineType() == 0 ? context.getMessage("motorcycle") : context.getMessage("bicycle"));
            machine.setUserCode(machineStatusFlag.getUserCode());
            machine.setFrame(machineStatusFlag.getFrame());
            machine.setLicense(machineStatusFlag.getLicense());
            machine.setMotor(machineStatusFlag.getMotor());
            machine.setMachineNO(machineStatusFlag.getMachineNO());
            machine.setIsOnline(machineStatusFlag.getOnline() ? context.getMessage("online") : context.getMessage("offline"));
            machine.setPosDt(machineStatusFlag.getPosDt());
            machine.setLastBorrowTime(machineStatusFlag.getLastBorrowTime());
            str = str.append(machineStatusFlag.getIsUse() ? context.getMessage("use") + ";" : context.getMessage("idle") + ";").append(machineStatusFlag.getIsAbnormal() ? context.getMessage("abnormal") + ";" : "").append(machineStatusFlag.getIsFault() ? context.getMessage("fault") + ";" : "").lastIndexOf(";") == str.length() - 1 ? str.deleteCharAt(str.length() - 1) : str;
            machine.setStatus(str.toString());
            machine.setSiteName(machineStatusFlag.getSiteName());
            exports.add(machine);
        });
        return exports;
    }

}
